// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef SPARSELU_IMPL_H
#define SPARSELU_IMPL_H

namespace Eigen {
namespace internal {

/** \ingroup SparseLU_Module
 * \class SparseLUImpl
 * Base class for sparseLU
 */
template<typename Scalar, typename StorageIndex>
class SparseLUImpl
{
  public:
	typedef Matrix<Scalar, Dynamic, 1> ScalarVector;
	typedef Matrix<StorageIndex, Dynamic, 1> IndexVector;
	typedef Matrix<Scalar, Dynamic, Dynamic, ColMajor> ScalarMatrix;
	typedef Map<ScalarMatrix, 0, OuterStride<>> MappedMatrixBlock;
	typedef typename ScalarVector::RealScalar RealScalar;
	typedef Ref<Matrix<Scalar, Dynamic, 1>> BlockScalarVector;
	typedef Ref<Matrix<StorageIndex, Dynamic, 1>> BlockIndexVector;
	typedef LU_GlobalLU_t<IndexVector, ScalarVector> GlobalLU_t;
	typedef SparseMatrix<Scalar, ColMajor, StorageIndex> MatrixType;

  protected:
	template<typename VectorType>
	Index expand(VectorType& vec, Index& length, Index nbElts, Index keep_prev, Index& num_expansions);
	Index memInit(Index m, Index n, Index annz, Index lwork, Index fillratio, Index panel_size, GlobalLU_t& glu);
	template<typename VectorType>
	Index memXpand(VectorType& vec, Index& maxlen, Index nbElts, MemType memtype, Index& num_expansions);
	void heap_relax_snode(const Index n,
						  IndexVector& et,
						  const Index relax_columns,
						  IndexVector& descendants,
						  IndexVector& relax_end);
	void relax_snode(const Index n,
					 IndexVector& et,
					 const Index relax_columns,
					 IndexVector& descendants,
					 IndexVector& relax_end);
	Index snode_dfs(const Index jcol,
					const Index kcol,
					const MatrixType& mat,
					IndexVector& xprune,
					IndexVector& marker,
					GlobalLU_t& glu);
	Index snode_bmod(const Index jcol, const Index fsupc, ScalarVector& dense, GlobalLU_t& glu);
	Index pivotL(const Index jcol,
				 const RealScalar& diagpivotthresh,
				 IndexVector& perm_r,
				 IndexVector& iperm_c,
				 Index& pivrow,
				 GlobalLU_t& glu);
	template<typename Traits>
	void dfs_kernel(const StorageIndex jj,
					IndexVector& perm_r,
					Index& nseg,
					IndexVector& panel_lsub,
					IndexVector& segrep,
					Ref<IndexVector> repfnz_col,
					IndexVector& xprune,
					Ref<IndexVector> marker,
					IndexVector& parent,
					IndexVector& xplore,
					GlobalLU_t& glu,
					Index& nextl_col,
					Index krow,
					Traits& traits);
	void panel_dfs(const Index m,
				   const Index w,
				   const Index jcol,
				   MatrixType& A,
				   IndexVector& perm_r,
				   Index& nseg,
				   ScalarVector& dense,
				   IndexVector& panel_lsub,
				   IndexVector& segrep,
				   IndexVector& repfnz,
				   IndexVector& xprune,
				   IndexVector& marker,
				   IndexVector& parent,
				   IndexVector& xplore,
				   GlobalLU_t& glu);

	void panel_bmod(const Index m,
					const Index w,
					const Index jcol,
					const Index nseg,
					ScalarVector& dense,
					ScalarVector& tempv,
					IndexVector& segrep,
					IndexVector& repfnz,
					GlobalLU_t& glu);
	Index column_dfs(const Index m,
					 const Index jcol,
					 IndexVector& perm_r,
					 Index maxsuper,
					 Index& nseg,
					 BlockIndexVector lsub_col,
					 IndexVector& segrep,
					 BlockIndexVector repfnz,
					 IndexVector& xprune,
					 IndexVector& marker,
					 IndexVector& parent,
					 IndexVector& xplore,
					 GlobalLU_t& glu);
	Index column_bmod(const Index jcol,
					  const Index nseg,
					  BlockScalarVector dense,
					  ScalarVector& tempv,
					  BlockIndexVector segrep,
					  BlockIndexVector repfnz,
					  Index fpanelc,
					  GlobalLU_t& glu);
	Index copy_to_ucol(const Index jcol,
					   const Index nseg,
					   IndexVector& segrep,
					   BlockIndexVector repfnz,
					   IndexVector& perm_r,
					   BlockScalarVector dense,
					   GlobalLU_t& glu);
	void pruneL(const Index jcol,
				const IndexVector& perm_r,
				const Index pivrow,
				const Index nseg,
				const IndexVector& segrep,
				BlockIndexVector repfnz,
				IndexVector& xprune,
				GlobalLU_t& glu);
	void countnz(const Index n, Index& nnzL, Index& nnzU, GlobalLU_t& glu);
	void fixupL(const Index n, const IndexVector& perm_r, GlobalLU_t& glu);

	template<typename, typename>
	friend struct column_dfs_traits;
};

} // end namespace internal
} // namespace Eigen

#endif
